Skip to content

feat(chain): Bitcoin merkle inclusion proofs (#112)#119

Merged
LiranCohen merged 1 commit into
mainfrom
feat/fastsync-merkle-proofs
Jun 9, 2026
Merged

feat(chain): Bitcoin merkle inclusion proofs (#112)#119
LiranCohen merged 1 commit into
mainfrom
feat/fastsync-merkle-proofs

Conversation

@LiranCohen

Copy link
Copy Markdown
Contributor

Summary

First piece of the ION fast-sync overlay (epic #111). MerkleProof / VerifyMerkleProof prove a transaction is included at a given index in a block whose merkle root the node has already PoW-verified (via its header chain) — without downloading the full block.

This is the trustless core of fast-sync: a fast-sync peer is an untrusted source, but an inclusion proof verified against the node's own header merkle root makes the claim "this anchor exists at block H, index I" impossible to forge. (A peer can still omit anchors — handled separately by trust-then-verify in #116.) Same trust philosophy as --esplora-api: untrusted hint, verified against our own PoW chain, fails closed.

What's here

  • internal/chain/merkleproof.go
    • MerkleProof(txids, index) → sibling branch (bottom-up).
    • VerifyMerkleProof(txid, index, branch, root) → folds per the index bits and requires a zero residual (i==0), so an inflated index can't be fabricated.
    • Classic witness=false txid tree (the one the header commits to); handles the odd-row last-element duplication and the single-tx (empty branch) case.
    • Documents the 64-byte second-preimage caveat: callers must validate the leaf is a real tx (the fast-sync client parses the anchoring tx anyway).
  • internal/chain/merkleproof_test.go — round-trips for sizes 1..100 cross-checked against btcd CalcMerkleRoot; negative paths (tampered branch / wrong index / wrong root / inflated index / wrong tx); bounds errors. Mutation-verified (a left/right swap fails the round-trip).
  • docs/design/ion-fast-sync-overlay.md — design summary + the 7-issue roadmap.

go test -race ./... green (27 packages).

Post-Deploy Monitoring & Validation

No additional operational monitoring required: pure, self-contained primitive with no wiring into runtime paths yet — it's consumed by later fast-sync issues (#113+).

Part of #111. Closes #112

🤖 Generated with Claude Code

First piece of the ION fast-sync overlay (epic #111). MerkleProof/VerifyMerkleProof
let a node prove a tx is included at a given index in a block whose merkle root it
already PoW-verified — without the full block. This is the trustless core: a
fast-sync peer is untrusted, but an inclusion proof verified against the node's own
header merkle root makes "this anchor exists at block H, index I" impossible to
forge (omission is handled separately by trust-then-verify).

- internal/chain/merkleproof.go: MerkleProof (sibling branch, bottom-up) +
  VerifyMerkleProof (fold per index bits, require i==0 residual so an inflated index
  can't be fabricated), over the classic witness=false txid tree, handling the
  odd-row last-element duplication and the single-tx (empty branch) case. Documents
  the 64-byte second-preimage caveat (callers validate the leaf is a real tx).
- internal/chain/merkleproof_test.go: round-trips for sizes 1..100 cross-checked
  against btcd CalcMerkleRoot; rejects tampered branch / wrong index / wrong root /
  inflated index / wrong tx; bounds-check errors. Mutation-verified (left/right swap).
- docs/design/ion-fast-sync-overlay.md: design summary + roadmap.

go test -race ./... green.

Co-authored-by: Liran Cohen <liranlasvegas@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@LiranCohen LiranCohen merged commit 1e9a0ce into main Jun 9, 2026
1 check passed
@LiranCohen LiranCohen deleted the feat/fastsync-merkle-proofs branch June 9, 2026 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fast-sync 1/7: Bitcoin merkle inclusion proofs (compute + verify)

1 participant